package com.bbcare.comm;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

import org.apache.commons.codec.binary.Base64;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import redis.clients.jedis.Jedis;
import sun.misc.BASE64Encoder;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sms.model.v20160927.SingleSendSmsRequest;
import com.aliyuncs.sms.model.v20160927.SingleSendSmsResponse;
import com.bbcare.sso.client.Account;
import com.bbcare.sso.client.Tenant;
import com.bbcare.util.FieldNotNullCheck;
import com.bbcare.util.WrappedHttpServletRequest;

/**
 * @name: 通用工具类
 * @author: DemonLee
 * @createTime: 2017.4.24
 * @description: 相关通用方法
 * @modify:
 */
public class ToolUtil {
    private final static Log logger = LogFactory.getLog(ToolUtil.class);

    private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

    // redis关闭
    public static void closeRedis(Jedis jedis) {
        if (null != jedis) {
            try {
                jedis.close();
                logger.warn("close redis connection...");
            } catch (Exception ex) {
                ex.printStackTrace();
                // throw (new
                // AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_REDIS_CONNECT_CLOSE_FAILED,
                // "Redis缓存关闭失败!"));
            }
        }
        return;
    }

    // 拼装redis-key
    public static String assembleKey(List<String> varList) {
        if (null == varList || 0 == varList.size()) {
            return null;
        }
        StringBuffer keyBuffer = new StringBuffer();
        int k = 0;
        for (k = 0; k < varList.size(); k++) {
            keyBuffer.append(varList.get(k));
            keyBuffer.append(Constants.COLON_SPLIT_STR);
        }
        return keyBuffer.substring(0, keyBuffer.length() - Constants.COLON_SPLIT_STR.length());
    }

    // 类型转换，去掉unchecked cast warning
    @SuppressWarnings("unchecked")
    public static <T> T typeCast(Object obj) {
        return (T) obj;
    }

    // 根据生日计算年龄，返回天数
    public static int getBirthAgeDay(String birthday) {
        int day = 0;
        try {
            Date birthdayDate = DateUtil.getDate_8(birthday);

            Calendar now = Calendar.getInstance();
            Calendar cal = Calendar.getInstance();
            cal.setTime(birthdayDate);
            long bet = now.getTimeInMillis() - cal.getTimeInMillis();
            if (bet < 0L) {
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_BIRTHDAY_EXPEND_NOW, "时间计算错误，出生日期大于当前时间！"));
            }
            day = (int) (bet / 86400000L);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_DATE_PARSE_ERROR, "时间解析错误，格式不正确！"));
        }
        return day;
    }

    /**
     * @name: 临床路径填写过的节点状态拼装
     * @author: DemonLee
     * @createTime: 2018.5.31
     * @param:
     * @return:
     * @modify:
     */
    public static void addValidFillNodeStatusList(List<String> nodeStatusList) {
        if (null == nodeStatusList) {
            return;
        }
        nodeStatusList.add(ConstantParams.PATIENT_CP_NODE_STATUS_FINISH_PART);
        nodeStatusList.add(ConstantParams.PATIENT_CP_NODE_STATUS_EXPIRED_FILL);
        nodeStatusList.add(ConstantParams.PATIENT_CP_NODE_STATUS_FINISH_ALL);

        return;
    }

    /**
     * @name: 临床路径节点处理状态拼装
     * @author: DemonLee
     * @createTime: 2018.5.31
     * @param:
     * @return:
     * @modify:
     */
    public static void addValidNodeDealStatusList(List<String> dealStatusList) {
        if (null == dealStatusList) {
            return;
        }
        dealStatusList.add(ConstantParams.CP_DEAL_STATUS_NORMAL);
        dealStatusList.add(ConstantParams.CP_DEAL_STATUS_FINISH);

        return;
    }

    // 按照任务触发方式，计算临床路径节点执行时间
    public static String calcCpNodeExecuteDate(Map<String, Object> pIn) {
        logger.debug("calcCpNodeExecuteDate pIn==" + pIn.toString());

        String currDate = (String) pIn.get("currDate");
        int iPrenDay = Integer.parseInt("" + pIn.get("prenDay"));
        String birthDay = (String) pIn.get("birthDay");
        String triggerType = (String) pIn.get("triggerType");
        int iNodeSeq = Integer.parseInt("" + pIn.get("nodeSeq"));
        int ageDay = Integer.parseInt("" + pIn.get("ageDay"));
        int executeDay = Integer.parseInt("" + pIn.get("executeDay"));
        // 建档问卷填写内容
        Map<String, Object> inputContData = typeCast(pIn.get("inputContData"));
        String executeDate = "";
        if (0 == iNodeSeq) {
            executeDate = currDate;
        }

        if (Constants.SCHEME_TASK_EXECUTE_TYPE_0.equals(triggerType)) {
            // 0：应用后触发（当天建档+第一次随访，然后按周期进行第n次随访）
            if (1 == iNodeSeq) {
                executeDate = currDate;
            } else if (iNodeSeq >= 2) {
                executeDate = DateUtil.calcDay(currDate, "+", executeDay);
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_1.equals(triggerType)) {
            // 1：纠正年龄触发（37周以下用纠正年龄(2岁内)，其他用出生年龄）
            if (iNodeSeq >= 1) {
                if (ageDay <= (2 * 365) && iPrenDay < Constants.PATIENT_PREMATURE_PREGNANT_DAY) {
                    executeDate = DateUtil.calcDay(birthDay, "+",
                            (Constants.PATIENT_NORMAL_PREGNANT_DAY - iPrenDay) + executeDay);
                } else {
                    executeDate = DateUtil.calcDay(birthDay, "+", executeDay);
                }
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_2.equals(triggerType)) {
            // 2：出生年龄触发（当天建档，后续随访日期按出生日期+周期计算）
            if (iNodeSeq >= 1) {
                executeDate = DateUtil.calcDay(birthDay, "+", executeDay);
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_3.equals(triggerType)) {
            // 3：出院后触发（出院日建档，后续随访按照出院日期+周期计算）
            String outHospitalDay = (String) pIn.get("outHospitalDay");
            if (StringUtils.isEmpty(outHospitalDay)) {
                // 从问卷答案中再找一遍
                if (MapUtils.isNotEmpty(inputContData)) {
                    outHospitalDay = (String) inputContData.get(ConstantParams.DE_CODE_FOR_LEAVEHOSPITAL_DATE);
                }
                if (StringUtils.isEmpty(outHospitalDay)) {
                    throw new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_TASKEXECUTETYPE_OUTHOSPITAL_PARAM,
                            "出院后触发随访任务需要填写出院日期！");
                }
            }
            if (iNodeSeq >= 1) {
                executeDate = DateUtil.calcDay(outHospitalDay, "+", executeDay);
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_4.equals(triggerType)) {
            // 4：初检孕周日期触发（孕产妇随访，初次孕检日建档）
            Integer firstChkPregWeek = (Integer) pIn.get("firstChkPregWeek");
            if (null == firstChkPregWeek || firstChkPregWeek <= 0) {
                if (MapUtils.isNotEmpty(inputContData)) {
                    String preWeekStr = (String) inputContData.get(ConstantParams.DE_CODE_FOR_FIRST_CHK_PREGWEEK);
                    if (StringUtils.isNotBlank(preWeekStr)) {
                        firstChkPregWeek = Integer.parseInt(preWeekStr);
                    }
                }
                if (null == firstChkPregWeek || firstChkPregWeek <= 0) {
                    throw new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                            "随访计划按初检孕周触发，初检孕周不能为空！");
                }
            }
            if (0 == iNodeSeq) {
                executeDate = currDate;
            } else {
                int dealDay = executeDay - firstChkPregWeek * 7;
                if (dealDay <= 0) {
                    dealDay = 0;
                }
                executeDate = DateUtil.calcDay(currDate, "+", dealDay);
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_5.equals(triggerType)) {
            // 5：末次月经日期触发（孕产妇随访）
            String lastMenstruationDate = (String) pIn.get("lastMenstruationDate");
            if (StringUtils.isBlank(lastMenstruationDate)) {
                if (MapUtils.isNotEmpty(inputContData)) {
                    lastMenstruationDate = (String) inputContData.get(ConstantParams.DE_CODE_FOR_LAST_MENSTRU_DATE);
                }
                if (StringUtils.isBlank(lastMenstruationDate)) {
                    throw new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                            "随访计划按末次月经日期触发，末次月经日期不能为空！");
                }
            }
            if (0 == iNodeSeq) {
                executeDate = currDate;
            } else {
                executeDate = DateUtil.calcDay(lastMenstruationDate, "+", executeDay);
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_6.equals(triggerType)) {
            // 6：应用后触发（当天建档，然后按周期进行第n次随访）
            if (iNodeSeq >= 1) {
                executeDate = DateUtil.calcDay(currDate, "+", executeDay);
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_7.equals(triggerType)) {
            // 7：分娩日期触发（孕产妇产后随访）
            String deliveryDate = (String) pIn.get("deliveryDate");
            if (StringUtils.isBlank(deliveryDate)) {
                if (MapUtils.isNotEmpty(inputContData)) {
                    deliveryDate = (String) inputContData.get(ConstantParams.DE_CODE_FOR_DELIVERY_DATE);
                }
                if (StringUtils.isBlank(deliveryDate)) {
                    throw new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                            "随访计划按分娩日期触发，分娩日期不能为空！");
                }
            }
            if (0 == iNodeSeq) {
                executeDate = currDate;
            } else {
                executeDate = DateUtil.calcDay(deliveryDate, "+", executeDay);
            }
        } else {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_TASKEXECUTETYPE_UNKNOWN, "任务触发方式未定义！"));
        }

        // 如果有首次随访日期，则第1次随访使用首次随访日期
        if (MapUtils.isNotEmpty(inputContData)) {
            String firstFollowDate = (String) inputContData.get(ConstantParams.DE_CODE_FOR_FIRST_FOLLOW_DATE);
            if (StringUtils.isNotBlank(firstFollowDate) && 1 == iNodeSeq) {
                executeDate = firstFollowDate;
            }
        }

        return executeDate;
    }

    /**
     * 从request域中获取body信息（前端传过来的json串）
     *
     * @param request
     * @return
     * @throws UnsupportedEncodingException
     */
    public static Map<String, Object> getRequestBody2Map(HttpServletRequest request) throws AppException {
        try {
            String jsonStr = new String(((WrappedHttpServletRequest) request).getBytes(), "UTF-8");
            JSONObject jsonArg = JSON.parseObject(jsonStr);
            Map<String, Object> data = jsonArg.getJSONObject(Constants.INF_INPUTPARAM_COMMONFIELD);
            return data;
        } catch (Exception ex) {
            ex.printStackTrace();
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_FORMAT_ERROR, "获取入参内容失败!"));
        }
    }

    /**
     * 校验入参根节点及json格式
     **/
    public static void checkInputRootNode(String arg) {
        if (StringUtils.isBlank(arg)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR, "入参信息为空！"));
        }
        try {
            com.alibaba.fastjson.JSON.parseObject(arg);
        } catch (Exception ex) {
            ex.printStackTrace();
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_FORMAT_ERROR,
                    Constants.API_INPUT_PARAMS_FORMAT_ERROR + "，非json格式！"));
        }

        return;
    }

    /**
     * 操作信息是否有操作时间等
     **/
    public static void fillOprInfo(Map<String, Object> arg) {
        if (MapUtils.isEmpty(arg)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，操作信息节点为空！"));
        }
        // 入参中有操作时间，则使用入参中的时间
        String opTime = (String) arg.get("opTime");
        if (StringUtils.isBlank(opTime)) {
            opTime = DateUtil.getSysDateA();
        }
        // 操作流水
        String updateAccept = SeqUtil.getSeqNo(Constants.SEQ_NO_FOR_SYSTEMID);

        arg.put("updateAccept", updateAccept);
        arg.put("updateTime", opTime);

        return;
    }

    /**
     * 校验入参根节点、json格式以及业务data节点
     **/
    public static void checkInputRoot(String arg) {
        if (StringUtils.isBlank(arg)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR, "入参信息为空！"));
        }
        com.alibaba.fastjson.JSONObject jsonArg = null;
        try {
            jsonArg = com.alibaba.fastjson.JSON.parseObject(arg);
        } catch (Exception ex) {
            ex.printStackTrace();
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_FORMAT_ERROR,
                    Constants.API_INPUT_PARAMS_FORMAT_ERROR + "，非json格式！"));
        }

        Map<String, Object> mapIn = jsonArg.getJSONObject(Constants.INF_INPUTPARAM_COMMONFIELD);
        if (null == mapIn) {
            // 前台必须传data节点，否则报错返回
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，无data节点！"));
        }

        return;
    }

    /**
     * 校验入参中节点是否为空 checkNode: 校验的节点名称; argInfo: 校验入参源; checkVarInfo: 待校验的变量
     * 支持String类型为空校验
     **/
    public static void checkInputInfo(String checkNode, Map<String, Object> argInfo, Map<String, Object> checkVarInfo) {
        if (MapUtils.isEmpty(checkVarInfo)) {
            return;
        }
        if (MapUtils.isEmpty(argInfo)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR, checkNode + "不能为空！"));
        }

        String chkVarStr = "";
        String chkVarValue = "";
        Iterator<String> iter = checkVarInfo.keySet().iterator();
        while (iter.hasNext()) {
            chkVarStr = "";
            chkVarValue = "";
            chkVarStr = iter.next();
            chkVarValue = (String) checkVarInfo.get(chkVarStr);

            try {
                if (StringUtils.isBlank(ToolUtil.getStringFromMap(argInfo, chkVarStr))) {
                    throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                            chkVarValue + "不能为空！"));
                }
            } catch (AppException e) {
                throw (e);
            } catch (Exception e) {
                List<Object> classIdList = ToolUtil.typeCast(argInfo.get(chkVarStr));// 文件id
                if (classIdList == null || classIdList.size() <= 0) {
                    throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                            chkVarValue + "不能为空！"));
                }

            }

        }

        return;
    }

    /**
     * 校验入参中节点至少有一个不能为空 支持String类型为空校验
     **/
    public static void checkInputNodeOneNotNull(String checkNodeStr, Map<String, Object> argInfo,
                                                Map<String, Object> checkVarInfo) {
        if (MapUtils.isEmpty(checkVarInfo)) {
            return;
        }
        if (MapUtils.isEmpty(argInfo)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，校验节点内容为空！"));
        }

        int chkFlag = 0;
        String chkVarStr = "";
        String chkVarValue = "";
        Iterator<String> iter = checkVarInfo.keySet().iterator();
        while (iter.hasNext()) {
            chkVarStr = "";
            chkVarValue = "";
            chkVarStr = iter.next();
            chkVarValue = (String) argInfo.get(chkVarStr);

            if (StringUtils.isNotBlank(chkVarValue)) {
                chkFlag = 1;
                break;
            }
        }
        if (0 == chkFlag) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    checkNodeStr + "至少有一个不能为空！"));
        }

        return;
    }

    /**
     * 校验入参中节点是否为空 checkNode: 校验的节点名称; argInfo: 校验入参源; checkVarInfo: 待校验的变量
     * 支持Integer类型为空及大于等于0校验
     **/
    public static void checkInputIntegerGe(String checkNode, Map<String, Object> argInfo,
                                           Map<String, Object> checkVarInfo) {
        if (MapUtils.isEmpty(checkVarInfo)) {
            return;
        }
        if (MapUtils.isEmpty(argInfo)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + checkNode + "节点为空！"));
        }

        String chkVarStr = "";
        String chkVarName = "";
        Integer chkVarValue = null;
        Iterator<String> iter = checkVarInfo.keySet().iterator();
        while (iter.hasNext()) {
            chkVarStr = "";
            chkVarName = "";
            chkVarStr = iter.next();
            chkVarName = (String) checkVarInfo.get(chkVarStr);

            chkVarValue = (Integer) argInfo.get(chkVarStr);
            if (null == chkVarValue || chkVarValue < 0) {
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                        chkVarName + "为空或传值错误！"));
            }
        }

        return;
    }

    /**
     * 校验入参中节点是否为空 checkNode: 校验的节点名称; argInfo: 校验入参源; checkVarInfo: 待校验的变量
     * 支持Integer类型为空校验
     **/
    public static void checkInputIntegerNotNull(String checkNode, Map<String, Object> argInfo,
                                                Map<String, Object> checkVarInfo) {
        if (MapUtils.isEmpty(checkVarInfo)) {
            return;
        }
        if (MapUtils.isEmpty(argInfo)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + checkNode + "节点为空！"));
        }

        String chkVarStr = "";
        String chkVarName = "";
        Integer chkVarValue = null;
        Iterator<String> iter = checkVarInfo.keySet().iterator();
        while (iter.hasNext()) {
            chkVarStr = "";
            chkVarName = "";
            chkVarStr = iter.next();
            chkVarName = (String) checkVarInfo.get(chkVarStr);

            chkVarValue = (Integer) argInfo.get(chkVarStr);
            if (null == chkVarValue) {
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                        chkVarName + "不能为空！"));
            }
        }

        return;
    }

    /**
     * 校验入参中节点是否为空 checkNode: 校验的节点名称; argInfo: 校验入参源; checkVarInfo: 待校验的变量
     * 支持各种类型的数据是否为空
     **/
    public static void checkInputMulti(String checkNode, Map<String, Object> argInfo,
                                       List<Map<String, Object>> checkVarList) {
        if (CollectionUtils.isEmpty(checkVarList)) {
            return;
        }
        if (MapUtils.isEmpty(argInfo)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + checkNode + "节点为空！"));
        }

        String chkVarId = null;// 校验变量名
        String chkVarName = null;// 校验变量中文名
        Integer chkVarType = null;// 校验变量的类型
        Integer chkRuleType = null;// 校验规则
        int c = 0;
        int csize = checkVarList.size();
        Map<String, Object> chekVarMap = new HashMap<String, Object>();
        for (c = 0; c < csize; c++) {
            chekVarMap = checkVarList.get(c);
            chkVarId = (String) chekVarMap.get("chkVarId");
            chkVarName = (String) chekVarMap.get("chkVarName");
            chkVarType = (Integer) chekVarMap.get("chkVarType");
            chkRuleType = (Integer) chekVarMap.get("chkRuleType");

            switch (chkVarType) {
                // String
                case Constants.COMMON_TYPE_FOR_STRING: {
                    if (Constants.CHECK_TYPE_FOR_NOTNULL == chkRuleType) {
                        // 非空
                        if (StringUtils.isBlank((String) argInfo.get(chkVarId))) {
                            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                                    chkVarName + "不能为空！"));
                        }
                    }
                    break;
                }
                // Integer
                case Constants.COMMON_TYPE_FOR_INTEGER: {
                    Integer chkVarValue = (Integer) argInfo.get(chkVarId);
                    if (Constants.CHECK_TYPE_FOR_NOTNULL == chkRuleType) {
                        // 非空
                        if (null == chkVarValue) {
                            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                                    chkVarName + "不能为空！"));
                        }
                    } else if (Constants.CHECK_TYPE_FOR_NOTNULL_AND_GEZERO == chkRuleType) {
                        // 非空且大于等于0
                        if (null == chkVarValue || chkVarValue < 0) {
                            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + chkVarName + "传值错误！"));
                        }
                    }
                    break;
                }
            }
        }

        return;
    }

    /**
     * 校验入参中List节点是否为空 checkNode: 校验的节点名称; argList: 校验入参源; checkVarInfo: 待校验的变量
     * 暂时只支持String类型为空校验
     **/
    public static void checkInputList(String checkNode, List<?> argList, Map<String, Object> checkVarInfo) {
        if (CollectionUtils.isEmpty(argList)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + checkNode + "节点为空！"));
        }
        if (MapUtils.isEmpty(checkVarInfo)) {
            return;
        }

        int i = 0;
        int isize = argList.size();
        Map<String, Object> objMap = null;
        for (i = 0; i < isize; i++) {
            objMap = typeCast(argList.get(i));
            checkInputInfo(checkNode, objMap, checkVarInfo);
        }

        return;
    }

    /**
     * 入参分页信息校验
     **/
    public static void checkPageInfo(Map<String, Object> pageMap) {
        Integer page = 1;
        Integer rows = 20;
        if (!MapUtils.isEmpty(pageMap)) {
            page = (Integer) pageMap.get("page");
            if (null == page || page <= 0) {
                page = 1;
            }
            rows = (Integer) pageMap.get("rows");
            if (null == rows || rows <= 0) {
                rows = 20;
            }
        }
        pageMap.put("page", page);
        pageMap.put("start", (page - 1) * rows);
        pageMap.put("end", rows);

        return;
    }

    // 数字校验
    public static boolean isNumeric(String str) {
        if (null == str) {
            return false;
        }
        Pattern pattern = Pattern.compile("(0|[0-9]+\\.?[0-9]+)|([1-9]\\d*)");
        Matcher isNum = pattern.matcher(str);
        if (!isNum.matches()) {
            return false;
        }
        return true;
    }

    /**
     * 年龄计算
     *
     * @throws ParseException
     **/
    public static void tranAgeYear(Map<String, Object> argMap) throws ParseException {
        if (!MapUtils.isEmpty(argMap)) {
            String ageTo = MapUtils.getString(argMap, "ageTo");
            String ageFrom = MapUtils.getString(argMap, "ageFrom");
            if (StringUtils.isNotEmpty(ageTo)) {
                if (!isNumeric(ageTo)) {
                    throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_FORMAT_ERROR, "年龄传入的参数不为整数！"));
                }
                Calendar to = Calendar.getInstance();
                Integer ageToStr = Integer.valueOf(String.valueOf(ageTo));
                to.add(Calendar.MONTH, -ageToStr);
                argMap.put("ageTo", DateUtil.getDate_8(to.getTime()));
            }
            if (StringUtils.isNotEmpty(ageFrom)) {
                if (!isNumeric(ageFrom)) {
                    throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_FORMAT_ERROR, "年龄传入的参数不为整！"));
                }
                Calendar from = Calendar.getInstance();
                Integer ageFromStr = Integer.valueOf(ageFrom);
                from.add(Calendar.MONTH, -ageFromStr);
                argMap.put("ageFrom", DateUtil.getDate_8(from.getTime()));
            }
        }
        return;
    }

    /* 通过分娩天数找到分娩日期 */
    public static void tranDeliveryYear(Map<String, Object> argMap) throws ParseException {
        if (!MapUtils.isEmpty(argMap)) {
            String beginDeliDay = MapUtils.getString(argMap, "beginDeliDay");
            String endDeliDay = MapUtils.getString(argMap, "endDeliDay");
            if (StringUtils.isNotEmpty(beginDeliDay)) {
                if (!isNumeric(beginDeliDay)) {
                    throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_FORMAT_ERROR,
                            "分娩天数传入的参数不为数字！"));
                }
                Calendar to = Calendar.getInstance();
                Integer beginDeliDayStr = Integer.valueOf(String.valueOf(beginDeliDay));
                to.add(Calendar.DATE, -beginDeliDayStr);
                argMap.put("endDeliDay", DateUtil.getDate_8(to.getTime()));
            }
            if (StringUtils.isNotEmpty(endDeliDay)) {
                if (!isNumeric(endDeliDay)) {
                    throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_FORMAT_ERROR, "分娩传入的参数不为数字！"));
                }
                Calendar from = Calendar.getInstance();
                Integer endDeliDayStr = Integer.valueOf(endDeliDay);
                from.add(Calendar.DATE, -endDeliDayStr);
                argMap.put("beginDeliDay", DateUtil.getDate_8(from.getTime()));
            }
        }
        return;
    }

    /**
     * 孕宝界面根据宝宝的孕周，280天得到妈妈预产期
     *
     * @param
     * @return
     * @author fangxm
     * @date 2018年6月1日
     * @description:
     */
    public static void tranExpectedDay(Map<String, Object> argMap) throws ParseException {
        if (!MapUtils.isEmpty(argMap)) {
            String preDay = MapUtils.getString(argMap, "chiPreDayStart");
            String preDayEnd = MapUtils.getString(argMap, "chiPreDayEnd");
            String startDay = "";
            String endDay = "";
            if (StringUtils.isNotEmpty(preDay)) {
                if (!isNumeric(preDay)) {
                    throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_FORMAT_ERROR,
                            "孕妈孕周传入的参数不为数字！"));
                }
                Calendar to = Calendar.getInstance();
                Integer preDayStr = Integer.valueOf(String.valueOf(preDay));
                preDayStr = Constants.PATIENT_NORMAL_PREGNANT_DAY - preDayStr;
                to.add(Calendar.DATE, preDayStr);
                startDay = DateUtil.getDate_8(to.getTime());
            }
            if (StringUtils.isNotEmpty(preDayEnd)) {
                if (!isNumeric(preDayEnd)) {
                    throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_FORMAT_ERROR,
                            "孕妈孕周传入的参数不为数字！"));
                }
                Calendar from = Calendar.getInstance();
                Integer preDayStr = Integer.valueOf(preDayEnd);
                preDayStr = Constants.PATIENT_NORMAL_PREGNANT_DAY - preDayStr;
                from.add(Calendar.DATE, preDayStr);
                endDay = DateUtil.getDate_8(from.getTime());
            }

            argMap.put("chiPreDayStart", startDay);
            argMap.put("chiPreDayEnd", endDay);

            // 孕宝管理左侧的的早 中晚 也需要根据 孕周计算，去得到末次月经
            String startPre = MapUtils.getString(argMap, "preDayStart");
            String endPre = MapUtils.getString(argMap, "preDayEnd");
            if (StringUtils.isNotEmpty(startPre)) {
                int start = Integer.valueOf(startPre);
                startPre = DateUtil.getYesterday(-start);
            }
            if (StringUtils.isNotEmpty(endPre)) {
                int end = Integer.valueOf(endPre);
                endPre = DateUtil.getYesterday(-end);
            }
            argMap.put("preDayStart", endPre);
            argMap.put("preDayEnd", startPre);
        }
        return;
    }

    // 是否早产
    public static boolean isPrematureBirth(String birthday, Integer pregnancyWeek) {
        boolean flag = false;
        try {
            Date birthdayDate = DateUtil.getDate_8(birthday);
            Calendar now = Calendar.getInstance();
            Calendar cal = Calendar.getInstance();
            cal.setTime(birthdayDate);
            int year = now.get(Calendar.YEAR) - cal.get(Calendar.YEAR);
            int day = now.get(Calendar.DAY_OF_MONTH) - cal.get(Calendar.DAY_OF_MONTH);
            int month = now.get(Calendar.MONTH) - cal.get(Calendar.MONTH);

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。

            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }
            if (null == pregnancyWeek || 0 == pregnancyWeek || pregnancyWeek >= 259
                    || (year >= 2 && month >= 0 && day >= 0)) { // 孕周大于37
                // 或者
                // 大于2岁
                // 按正常年龄算
                flag = false;
            } else {
                flag = true;
            }
        } catch (Exception e) {
            logger.error("计算年龄报错", e);
        }
        return flag;
    }

    // 矫正年龄
    public static Long getCorrect(String birthday, Integer pregnancyWeek) {
        // TODO Auto-generated method stub
        // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Long time = new Date().getTime();
        try {
            Date birthdayDate = DateUtil.getDate_8(birthday);

            Calendar now = Calendar.getInstance();
            Calendar cal = Calendar.getInstance();
            cal.setTime(birthdayDate);
            int year = now.get(Calendar.YEAR) - cal.get(Calendar.YEAR);
            int day = now.get(Calendar.DAY_OF_MONTH) - cal.get(Calendar.DAY_OF_MONTH);
            int month = now.get(Calendar.MONTH) - cal.get(Calendar.MONTH);

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。

            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }
            if (null == pregnancyWeek || 0 == pregnancyWeek || pregnancyWeek >= 259
                    || (year >= 2 && month >= 0 && day >= 0)) { // 孕周大于37
                // 或者
                // 大于2岁
                // 按正常年龄算
                time = birthdayDate.getTime();
            } else {
                time = birthdayDate.getTime() + (280 - pregnancyWeek) * 86400000L;
            }
        } catch (Exception e) {
            logger.error("计算年龄报错", e);
        }
        return time;
    }

    // 根据出生日期和预产期计算孕周，返回天数
    public static int calPrenDayByBirthAndExpect(String birthday, String expectedDay) {
        int day = 0;
        if (!StringUtils.isEmpty(birthday) && !StringUtils.isEmpty(expectedDay)) {
            try {
                Date birthdayDate = DateUtil.getDate_8(birthday);
                Date expectedDate = DateUtil.getDate_8(expectedDay);

                Calendar exp = Calendar.getInstance();
                Calendar bir = Calendar.getInstance();
                exp.setTime(expectedDate);
                bir.setTime(birthdayDate);
                long expTime = exp.getTimeInMillis();
                long birTime = bir.getTimeInMillis();
                long bet = birTime - expTime;
                day = Constants.PATIENT_NORMAL_PREGNANT_DAY + (int) (bet / 86400000L);
                // 后续考虑最小孕周和最大孕周的情况，加校验，这里先只校验小于0的情况
                if (day < 0) {
                    day = 0;
                }
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_DATE_PARSE_ERROR, "时间解析错误，格式不正确！"));
            }
        }
        return day;
    }

    // 从问卷中解析用户基本信息
    public static Map<String, Object> parseUserInfoByQues(Map<String, Object> inPut) {
        Map<String, Object> inMap = new HashMap<String, Object>(inPut);
        Map<String, Object> outMap = new HashMap<String, Object>();
        // 手机号码
        String phoneNo = (String) inMap.get(Constants.QUESTION_ID_FOR_PHONENO);

        if (!StringUtils.isBlank(phoneNo)) {
            phoneNo = phoneNo.trim();
            outMap.put("phoneNo", phoneNo);
        }
        // 患者姓名
        String userName = (String) inMap.get(Constants.QUESTION_ID_FOR_PATIENTNAME);
        if (!StringUtils.isBlank(userName)) {
            userName = userName.trim();
            outMap.put("userName", userName);
            outMap.put("firstName", userName.substring(0, 1));
        }
        // 性别
        String gender = (String) inMap.get(Constants.QUESTION_ID_FOR_GENDER);
        if (!StringUtils.isBlank(gender)) {
            gender = gender.trim();
            // 转换性别
            if (Constants.GENDER_ALIAS_FOR_MALE.equals(gender)) {
                gender = Constants.GENDER_FOR_MALE;
            } else if (Constants.GENDER_ALIAS_FOR_FEMALE.equals(gender)) {
                gender = Constants.GENDER_FOR_FEMALE;
            } else if (!Constants.GENDER_FOR_MALE.equals(gender) && !Constants.GENDER_FOR_FEMALE.equals(gender)) {
                gender = Constants.GENDER_FOR_MALE;
            }
            outMap.put("gender", gender);
        }

        // 出生日期
        String birthday = (String) inMap.get(Constants.QUESTION_ID_FOR_BIRTHDAY);
        if (!StringUtils.isBlank(birthday)) {
            birthday = birthday.trim();
            outMap.put("birthday", birthday);
        }
        // 预产期
        String expectedDay = (String) inMap.get(Constants.QUESTION_ID_FOR_EXPECTEDDAY);
        if (!StringUtils.isBlank(expectedDay)) {
            expectedDay = expectedDay.trim();
        }

        String idCard = (String) inMap.get(Constants.QUESTION_ID_FOR_IDCARD);
        if (!StringUtils.isBlank(idCard)) {
            idCard = idCard.trim();
            outMap.put("idCard", idCard);
        }

        // 出生胎龄(孕周)
        String pregnancyDayStr = (String) inMap.get(Constants.QUESTION_ID_FOR_PREGNANCYWEEK);
        int pregnancyDay = 0;
        // 再考虑从问卷中获取，问卷存储格式：[39,5]
        if (StringUtils.isEmpty(pregnancyDayStr) && !MapUtils.isEmpty(inMap)) {
            String preStr = (String) inMap.get(Constants.QUESTION_ID_FOR_PREGNANCYDAY);
            if (!StringUtils.isEmpty(preStr)) {
                String preArr[] = preStr.split(Constants.COMMA_SPLIT_STR);
                if (null != preArr && 2 == preArr.length) {
                    String preWeekStr = preArr[0].substring(1);
                    String preDayStr = preArr[1].substring(0, preArr[1].length() - 1);
                    int preWeek = Integer.parseInt(preWeekStr);
                    int preDay = Integer.parseInt(preDayStr);
                    pregnancyDay = preWeek * Constants.PREGNANCY_CALC_UNIT_WEEK + preDay;
                }
            }
        } else {
            pregnancyDay = Integer.parseInt(pregnancyDayStr);
        }

        if (!StringUtils.isEmpty(birthday) && !StringUtils.isEmpty(expectedDay) && pregnancyDay <= 0) {
            // 根据生日和预产期计算孕周
            pregnancyDay = calPrenDayByBirthAndExpect(birthday, expectedDay);
        }

        // 孕周未填，默认280
        if (pregnancyDay <= 0) {
            pregnancyDay = Constants.PATIENT_NORMAL_PREGNANT_DAY;
        }
        // 预产期未填，默认与出生日期一致
        if (StringUtils.isEmpty(expectedDay)) {
            expectedDay = birthday;
        }
        outMap.put("pregnancyDay", pregnancyDay + "");
        outMap.put("expectedDay", expectedDay + "");

        return outMap;
    }

    /**
     * 先进行MD5摘要再进行Base64编码获取摘要字符串
     *
     * @param str
     * @return
     */
    public static String base64AndMD5(String str) {
        if (str == null) {
            throw new IllegalArgumentException("入参为空");
        }
        return base64AndMD5(toBytes(str));
    }

    /**
     * 先进行MD5摘要再进行Base64编码获取摘要字符串
     *
     * @return
     */
    public static String base64AndMD5(byte[] bytes) {
        if (bytes == null) {
            throw new IllegalArgumentException("数组不可以为空");
        }
        try {
            final MessageDigest md = MessageDigest.getInstance("MD5");
            md.reset();
            md.update(bytes);
            final Base64 base64 = new Base64();
            final byte[] enbytes = base64.encode(md.digest());
            return new String(enbytes);
        } catch (final NoSuchAlgorithmException e) {
            throw new IllegalArgumentException("无法进行MD5加密");
        }
    }

    /**
     * String转换为字节数组
     *
     * @param str
     * @return
     */
    private static byte[] toBytes(final String str) {
        if (str == null) {
            return null;
        }
        try {
            return str.getBytes(Constants.UTF8);
        } catch (final UnsupportedEncodingException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * UTF-8编码转换为ISO-9959-1
     *
     * @param str
     * @return
     */
    public static String utf8ToIso88591(String str) {
        if (str == null) {
            return str;
        }

        try {
            return new String(str.getBytes("UTF-8"), "ISO-8859-1");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * ISO-9959-1编码转换为UTF-8
     *
     * @param str
     * @return
     */
    public static String iso88591ToUtf8(String str) {
        if (str == null) {
            return str;
        }

        try {
            return new String(str.getBytes("ISO-8859-1"), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * 计算签名
     *
     * @param secret               APP密钥
     * @param method               HttpMethod
     * @param path
     * @param headers
     * @param querys
     * @param bodys
     * @param signHeaderPrefixList 自定义参与签名Header前缀
     * @return 签名后的字符串
     */
    public static String sign(String secret, String method, String path, Map<String, String> headers,
                              Map<String, String> querys, Map<String, String> bodys,
                              List<String> signHeaderPrefixList) {
        try {
            Mac hmacSha256 = Mac.getInstance(Constants.HMAC_SHA256);
            byte[] keyBytes = secret.getBytes(Constants.UTF8);
            hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, Constants.HMAC_SHA256));

            return new String(Base64.encodeBase64(
                    hmacSha256.doFinal(buildStringToSign(method, path, headers, querys, bodys, signHeaderPrefixList)
                            .getBytes(Constants.UTF8))),
                    Constants.UTF8);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 构建待签名字符串
     *
     * @param method
     * @param path
     * @param headers
     * @param querys
     * @param bodys
     * @param signHeaderPrefixList
     * @return
     */
    private static String buildStringToSign(String method, String path, Map<String, String> headers,
                                            Map<String, String> querys, Map<String, String> bodys,
                                            List<String> signHeaderPrefixList) {
        StringBuilder sb = new StringBuilder();

        sb.append(method.toUpperCase()).append(Constants.LF);
        if (null != headers) {
            if (null != headers.get(Constants.HTTP_HEADER_ACCEPT)) {
                sb.append(headers.get(Constants.HTTP_HEADER_ACCEPT));
            }
            sb.append(Constants.LF);
            if (null != headers.get(Constants.HTTP_HEADER_CONTENT_MD5)) {
                sb.append(headers.get(Constants.HTTP_HEADER_CONTENT_MD5));
            }
            sb.append(Constants.LF);
            if (null != headers.get(Constants.HTTP_HEADER_CONTENT_TYPE)) {
                sb.append(headers.get(Constants.HTTP_HEADER_CONTENT_TYPE));
            }
            sb.append(Constants.LF);
            if (null != headers.get(Constants.HTTP_HEADER_DATE)) {
                sb.append(headers.get(Constants.HTTP_HEADER_DATE));
            }
        }
        sb.append(Constants.LF);
        sb.append(buildHeaders(headers, signHeaderPrefixList));
        sb.append(buildResource(path, querys, bodys));

        return sb.toString();
    }

    /**
     * 构建待签名Path+Query+BODY
     *
     * @param path
     * @param querys
     * @param bodys
     * @return 待签名
     */
    private static String buildResource(String path, Map<String, String> querys, Map<String, String> bodys) {
        StringBuilder sb = new StringBuilder();

        if (!StringUtils.isBlank(path)) {
            sb.append(path);
        }
        Map<String, String> sortMap = new TreeMap<String, String>();
        if (null != querys) {
            for (Map.Entry<String, String> query : querys.entrySet()) {
                if (!StringUtils.isBlank(query.getKey())) {
                    sortMap.put(query.getKey(), query.getValue());
                }
            }
        }

        if (null != bodys) {
            for (Map.Entry<String, String> body : bodys.entrySet()) {
                if (!StringUtils.isBlank(body.getKey())) {
                    sortMap.put(body.getKey(), body.getValue());
                }
            }
        }

        StringBuilder sbParam = new StringBuilder();
        for (Map.Entry<String, String> item : sortMap.entrySet()) {
            if (!StringUtils.isBlank(item.getKey())) {
                if (0 < sbParam.length()) {
                    sbParam.append(Constants.SPE3);
                }
                sbParam.append(item.getKey());
                if (!StringUtils.isBlank(item.getValue())) {
                    sbParam.append(Constants.SPE4).append(item.getValue());
                }
            }
        }
        if (0 < sbParam.length()) {
            sb.append(Constants.SPE5);
            sb.append(sbParam);
        }

        return sb.toString();
    }

    /**
     * 构建待签名Http头
     *
     * @param headers              请求中所有的Http头
     * @param signHeaderPrefixList 自定义参与签名Header前缀
     * @return 待签名Http头
     */
    private static String buildHeaders(Map<String, String> headers, List<String> signHeaderPrefixList) {
        StringBuilder sb = new StringBuilder();

        if (null != signHeaderPrefixList) {
            signHeaderPrefixList.remove(Constants.X_CA_SIGNATURE);
            signHeaderPrefixList.remove(Constants.HTTP_HEADER_ACCEPT);
            signHeaderPrefixList.remove(Constants.HTTP_HEADER_CONTENT_MD5);
            signHeaderPrefixList.remove(Constants.HTTP_HEADER_CONTENT_TYPE);
            signHeaderPrefixList.remove(Constants.HTTP_HEADER_DATE);
            Collections.sort(signHeaderPrefixList);
            if (null != headers) {
                Map<String, String> sortMap = new TreeMap<String, String>();
                sortMap.putAll(headers);
                StringBuilder signHeadersStringBuilder = new StringBuilder();
                for (Map.Entry<String, String> header : sortMap.entrySet()) {
                    if (isHeaderToSign(header.getKey(), signHeaderPrefixList)) {
                        sb.append(header.getKey());
                        sb.append(Constants.COLON_SPLIT_STR);
                        if (!StringUtils.isBlank(header.getValue())) {
                            sb.append(header.getValue());
                        }
                        sb.append(Constants.LF);
                        if (0 < signHeadersStringBuilder.length()) {
                            signHeadersStringBuilder.append(Constants.COMMA_SPLIT_STR);
                        }
                        signHeadersStringBuilder.append(header.getKey());
                    }
                }
                headers.put(Constants.X_CA_SIGNATURE_HEADERS, signHeadersStringBuilder.toString());
            }
        }

        return sb.toString();
    }

    /**
     * Http头是否参与签名 return
     */
    private static boolean isHeaderToSign(String headerName, List<String> signHeaderPrefixList) {
        if (StringUtils.isBlank(headerName)) {
            return false;
        }

        if (headerName.startsWith(Constants.CA_HEADER_TO_SIGN_PREFIX_SYSTEM)) {
            return true;
        }

        if (null != signHeaderPrefixList) {
            for (String signHeaderPrefix : signHeaderPrefixList) {
                if (headerName.equalsIgnoreCase(signHeaderPrefix)) {
                    return true;
                }
            }
        }

        return false;
    }

    public static Map<String, Object> getSessionInfo(HttpServletRequest request, String sessionAccoutKey) {
        Map<String, Object> outRet = new HashMap<String, Object>();

        HttpSession session = request.getSession(true);
        if (null == session) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_SESSION_ISNULL, "session为空！"));
        }
        Account account = (Account) session.getAttribute(sessionAccoutKey);
        if (null == account) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_SESSION_VALUEISNULL, "获取session账号值为空！"));
        }
        Tenant tenant = (Tenant) account.getTenant();
        if (null == tenant) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_SESSION_VALUEISNULL, "获取session租户值为空！"));
        }

        outRet.put("loginId", account.getUsername());
        outRet.put("authorName", account.getAlias());
        outRet.put("tenantId", tenant.getId());
        outRet.put("tenantName", tenant.getName());

        outRet.put("authorType", tenant.getType());
        outRet.put("authorId", account.getRelationId());
        // 项目id
        outRet.put("projectId", "");
        outRet.put("projectRoleId", "");
        outRet.put("roleType", "");
        com.alibaba.fastjson.JSONArray array = tenant.getAuProjectRoleRel();
        if (array != null && array.size() > 0) {
            for (int i = 0; i < array.size(); i++) {
                JSONObject json = array.getJSONObject(i);
                if (json.getInteger("selectStatus") == 1) {
                    outRet.put("projectId", json.getString("projectId"));
                    outRet.put("projectRoleId", json.getString("id"));
                    outRet.put("roleType", json.getString("roleType"));
                }
            }
        }

        outRet.put("deptIdList", tenant.getTenantRootGroupIdList());

        // 租户类型：1、科室，2、医院，3、多中心，4、医联体
        outRet.put("groupType", tenant.getType());
        outRet.put("rootGroupId", tenant.getRootGroupId());
        if (Constants.TENANT_GROUP_TYPE_FOR_DEPT == tenant.getType()) {
            outRet.put("deptId", tenant.getRootGroupId());
        } else if (Constants.TENANT_GROUP_TYPE_FOR_HOSPITAL == tenant.getType()) {
            // outRet.put("hospitalId", tenant);
        } else if (Constants.TENANT_GROUP_TYPE_FOR_MULCENTER == tenant.getType()) {
            // TODO
        } else if (Constants.TENANT_GROUP_TYPE_FOR_UNION == tenant.getType()) {
            // TODO
        }

        logger.warn("outRet==" + outRet.toString());

        return outRet;
    }

    /**
     * @param request
     * @return
     * @throws IOException
     */
    public static String getRequestBody(HttpServletRequest request) throws IOException {
        ByteArrayOutputStream body = new ByteArrayOutputStream();
        InputStream inputStream = request.getInputStream();

        byte[] buffer = new byte[1024];
        int flag = 0;
        while ((flag = inputStream.read(buffer)) != -1) {
            body.write(buffer, 0, flag);
        }
        return new String(body.toByteArray(), "UTF-8");
    }

    /**
     * @param request
     * @return IData
     * @Title: getParam
     * @Description: 获取请求参数集合
     * @author: ht
     */
    public static Map<String, Object> getParam(HttpServletRequest request) {
        Map<String, Object> param = new HashMap<String, Object>();
        Enumeration<?> enu = request.getParameterNames();
        while (enu.hasMoreElements()) {
            String paramKey = (String) enu.nextElement();
            String value = request.getParameter(paramKey);
            // 中文转码
            try {
                value = new String(value.getBytes(Constants.ISO), Constants.UTF8);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            param.put(paramKey, value);
        }
        return param;
    }

    /**
     * 字典排序
     *
     * @param timestamp
     * @param nonce
     * @param token
     * @return
     * @throws Exception
     */
    public static String getSignature(String timestamp, String nonce, String token) throws Exception {
        String maxString = "";// 排后面
        String minString = "";// 排前面
        if (timestamp.compareTo(nonce) < 0) {
            maxString = nonce;
            minString = timestamp;
        } else {
            maxString = timestamp;
            minString = nonce;
        }

        if (token.compareTo(maxString) > 0) {
            token = minString + maxString + token;
        } else if (token.compareTo(minString) < 0) {
            token = token + minString + maxString;
        } else {
            token = minString + token + maxString;
        }
        return SHA1Encode(token);
    }

    /**
     * SHA1Encode
     *
     * @param sourceString
     * @return String
     * @todo //sha1加密
     * @Exception
     * @update:
     */
    public static String SHA1Encode(String sourceString) {
        String resultString = null;
        try {
            resultString = new String(sourceString);
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            resultString = byte2hexString(md.digest(resultString.getBytes()));
        } catch (Exception ex) {
        }
        return resultString;
    }

    /**
     * byte2hexString
     *
     * @param bytes
     * @return String
     * @todo
     * @Exception
     */
    public final static String byte2hexString(byte[] bytes) {
        StringBuffer buf = new StringBuffer(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++) {
            if (((int) bytes[i] & 0xff) < 0x10) {
                buf.append("0");
            }
            buf.append(Long.toString((int) bytes[i] & 0xff, 16));
        }
        return buf.toString().toUpperCase();
    }

    /**
     * @param in
     * @return String
     * @Title: readStreamParameter
     * @Description: 从输入流读取post参数
     */
    public static String readStreamParameter(ServletInputStream in) {
        StringBuilder buffer = new StringBuilder();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(in, Constants.UTF8));
            String line = null;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != reader) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return buffer.toString();
    }

    /**
     * @param doc
     * @return IData
     * @Title: getXmlElementData
     * @Description: 解析xml获取子节点键值对
     * @author: ht
     */
    public static Map<String, Object> getXmlElementData(String xmlStr) {
        Map<String, Object> data = new HashMap<String, Object>();
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            org.w3c.dom.Document doc = builder.parse(new InputSource(new StringReader(xmlStr)));

            org.w3c.dom.Element root = doc.getDocumentElement();
            NodeList nodeList = root.getChildNodes();
            if (nodeList != null) {
                getNodeList(nodeList, data);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * @param nodeList
     * @return IData
     * @Title: getNodeList
     * @Description: 获取子节点值
     * @author: ht
     */
    private static Map<String, Object> getNodeList(NodeList nodeList, Map<String, Object> data) {
        if (nodeList != null) {
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node childNode = nodeList.item(i);
                if (childNode.hasChildNodes()) {
                    getNodeList(childNode.getChildNodes(), data);
                } else {
                    data.put(childNode.getParentNode().getNodeName(), childNode.getNodeValue());
                }
            }
        }
        return data;
    }

    /**
     * 去掉url中的路径，留下请求参数部分
     *
     * @param strURL url地址
     * @return url请求参数部分
     */
    private static String TruncateUrlPage(String strURL) {
        String strAllParam = null;
        String[] arrSplit = null;
        strURL = strURL.trim();
        arrSplit = strURL.split("[?]");
        if (strURL.length() > 1) {
            if (arrSplit.length > 1) {
                if (arrSplit[1] != null) {
                    strAllParam = arrSplit[1];
                }
            }
        }
        return strAllParam;
    }

    /**
     * 解析出url参数中的键值对 如 "index.jsp?Action=del&id=123"，解析出Action:del,id:123存入map中
     *
     * @param URL url地址
     * @return url请求参数部分
     */
    public static Map<String, String> URLRequest(String URL) {
        Map<String, String> mapRequest = new HashMap<String, String>();
        String[] arrSplit = null;
        String strUrlParam = TruncateUrlPage(URL);
        if (strUrlParam == null) {
            return mapRequest;
        }
        // 每个键值为一组 www.2cto.com
        arrSplit = strUrlParam.split("[&]");
        for (String strSplit : arrSplit) {
            String[] arrSplitEqual = null;
            arrSplitEqual = strSplit.split("[=]");
            // 解析出键值
            if (arrSplitEqual.length > 1) {
                // 正确解析
                mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);
            } else {
                if (arrSplitEqual[0] != "") {
                    // 只有参数没有值，不加入
                    mapRequest.put(arrSplitEqual[0], "");
                }
            }
        }
        return mapRequest;
    }

    /**
     * 从request域中获取body信息（前端传过来的json串）
     *
     * @param request
     * @return
     * @throws UnsupportedEncodingException
     */
    public static JSONObject getRequestBody2Json(HttpServletRequest request) throws AppException {
        try {
            String jsonStr = new String(((WrappedHttpServletRequest) request).getBytes(), "UTF-8");
            JSONObject jsonArg = JSON.parseObject(jsonStr);
            JSONObject data = jsonArg.getJSONObject(Constants.INF_INPUTPARAM_COMMONFIELD);
            return data;
        } catch (Exception ex) {
            ex.printStackTrace();
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_FORMAT_ERROR, "获取入参内容失败!"));
        }
    }

    // 将中文转化成中文拼音
    public static String getEname(String name) throws BadHanyuPinyinOutputFormatCombination {
        HanyuPinyinOutputFormat pyFormat = new HanyuPinyinOutputFormat();
        pyFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        pyFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        pyFormat.setVCharType(HanyuPinyinVCharType.WITH_V);
        return PinyinHelper.toHanYuPinyinString(name, pyFormat, "", true);
    }

    // 将姓名转成简拼
    public static String getNameInitial(String name) throws BadHanyuPinyinOutputFormatCombination {
        String nameOut = "";// 返回首字母组成的字符串
        // 将姓名解析
        char[] stringArr = name.toCharArray();
        StringBuffer buf = new StringBuffer();// 用户
        for (int i = 0; i < stringArr.length; i++) {
            // 获取当前字符的拼音
            String namestr = getEname(String.valueOf(stringArr[i]));
            if (!StringUtils.isBlank(namestr)) {
                buf.append(namestr.substring(0, 1));
            }
        }
        nameOut = buf.toString();
        logger.debug("nameOut  : " + nameOut);
        return nameOut;
    }

    /**
     * 将String 转成List<String>
     *
     * @param
     * @return
     * @author fangxm
     * @date 2018年5月6日
     * @description:
     */
    public static List<String> str2List(String sendPersonId) {
        List<String> list = new ArrayList<String>();
        String[] strarr = sendPersonId.split(",");
        for (int i = 0; i < strarr.length; i++) {
            String temp = strarr[i];
            if (temp != null && !temp.equals("")) {
                list.add(temp);
            }
        }
        return list;
    }

    // 根据生日计算年龄
    public static String getAgeByBirthday(String birthday) throws ParseException {
        StringBuilder builder = new StringBuilder();
        Calendar now = Calendar.getInstance();
        Calendar cal = Calendar.getInstance();
        // int age = 0;
        if (!now.getTime().before(DateUtil.getDate_8(birthday))) {
            int yearNow = now.get(Calendar.YEAR);
            int monthNow = now.get(Calendar.MONTH);
            int dayOfMonthNow = now.get(Calendar.DAY_OF_MONTH);

            cal.setTime(DateUtil.getDate_8(birthday));
            int yearBirth = cal.get(Calendar.YEAR);
            int monthBirth = cal.get(Calendar.MONTH);
            int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);

            int day = dayOfMonthNow - dayOfMonthBirth;
            int month = monthNow - monthBirth;
            int year = yearNow - yearBirth;

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。

            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }

            int week = 0;
            // 暂时展示 一个单位 岁、或月、周、天

            if (year > 0) {
                builder.append(year).append("岁");
            }

            if (month > 0 && year >= 0) {
                builder.append(month).append("个月");
            } else if (day > 0 && month >= 0 && year >= 0) {
                if (day > 7) {// 展示周
                    week = day / 7;
                    builder.append(week).append("周");
                } else {
                    builder.append(day).append("天");
                }
            } else {
                builder.append("0").append("天");
            }
        } else {
            builder.append("0").append("天");
        }
        return builder.toString();
    }

    public static String getPregnancyStr(int pregnancy) {
        StringBuilder builder = new StringBuilder();
        String week = String.valueOf(pregnancy / 7);
        String day = String.valueOf(pregnancy % 7);
        builder.append(week);
        builder.append("周");
        builder.append(day);
        builder.append("天");
        return builder.toString();
    }

    // 从map中 获取value 返回string
    public static String getStringFromMap(Map<String, Object> map, String key) {
        String value = null;
        Object obj = null;
        if (null == map) {
            return null;
        }
        obj = map.get(key);
        if (null == obj) {
            return null;
        }
        value = obj.toString();
        return value;
    }

    /**
     * @param dealDate
     * @param addDay
     * @return
     * @throws ParseException
     */
    public static String nextDay(String dealDate, int addDay) throws ParseException {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateFormat.parse(dealDate));
        calendar.add(Calendar.DATE, addDay);
        return dateFormat.format(calendar.getTime());
    }

    /**
     * @param birthday      String 出生日期
     * @param pregnancyWeek Integer 孕周
     * @param testTime      String 创建时间，评估时间等
     * @param flag          Boolean true:计算纠正年龄，false:计算实际年龄
     * @return age String 年龄
     * @description 计算年龄 计算规则： 1、小于三个月的显示几周几天，(days<3*30) 2、小于1岁的显示几月龄几天，
     * (3*30<=days<1*365) 3、大于一岁的显示几岁几月龄，(1*365<=days<6*365)
     * 4、大于六岁的只显示岁。 (days>=6*365)
     */
    public static String getCorrectNew(String birthday, Integer pregnancyWeek, String testTime, boolean flag) {
        // TODO Auto-generated method stub
        // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Long time = (long) 0;
        try {
            if (StringUtils.isBlank(birthday)) {
                return "";
            }
            Date birthdayDate = DateUtil.getDate_8(birthday);

            Calendar now = Calendar.getInstance();
            Calendar cal = Calendar.getInstance();
            cal.setTime(birthdayDate);
            if (!StringUtils.isBlank(testTime)) {
                Date testTimeDate = DateUtil.getDate_8(testTime);
                now.setTime(testTimeDate);
                time = testTimeDate.getTime();
            } else {
                time = new Date().getTime();
            }
            int year = now.get(Calendar.YEAR) - cal.get(Calendar.YEAR);
            int day = now.get(Calendar.DAY_OF_MONTH) - cal.get(Calendar.DAY_OF_MONTH);
            int month = now.get(Calendar.MONTH) - cal.get(Calendar.MONTH);

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。

            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }
            time = time - birthdayDate.getTime();
            if (flag) {
                if (null == pregnancyWeek || 0 == pregnancyWeek || pregnancyWeek >= 259
                        || (year >= 2 && month >= 0 && day >= 0)) { // 孕周大于37
                    // 或者
                    // 大于2岁
                    // 按正常年龄算
                } else {
                    time = time - (280 - pregnancyWeek) * 86400000L;
                }
            }
        } catch (Exception e) {
            logger.error("计算年龄报错", e);
        }

        int days = (int) (time / 86400000L);
        String age = "";
        if (days < 3 * Constants.MONTH_DAY) {
            int week = days / Constants.PREGNANCY_CALC_UNIT_WEEK;
            int day = days % Constants.PREGNANCY_CALC_UNIT_WEEK;
            if (week != 0) {
                age += week + "周";
            }
            age += day + "天";
        } else if (days < 1 * Constants.YEAR_DAY) {
            int month = days / Constants.MONTH_DAY;
            int day = days % Constants.MONTH_DAY;
            if (month != 0) {
                age += month + "月龄";
            }
            if (day != 0) {
                age += day + "天";
            }
        } else if (days < 6 * Constants.YEAR_DAY) {
            int year = days / Constants.YEAR_DAY;
            int month = (days % Constants.YEAR_DAY) / Constants.MONTH_DAY;
            if (year != 0) {
                age += year + "岁";
            }
            if (month != 0) {
                age += month + "月龄";
            }
        } else {
            int year = days / Constants.YEAR_DAY;
            if (year != 0) {
                age += year + "岁";
            }
        }
        return age;
    }

    /**
     * @param birthday      String 出生日期
     * @param pregnancyWeek Integer 孕周
     * @param testTime      String 创建时间，评估时间等
     * @param flag          Boolean true:计算纠正年龄，false:计算实际年龄
     * @return age String 年龄
     * @description 计算出生天数 计算规则： 1、小于三个月的显示几周几天，(days<3*30) 2、小于1岁的显示几月龄几天，
     * (3*30<=days<1*365) 3、大于一岁的显示几岁几月龄，(1*365<=days<6*365)
     * 4、大于六岁的只显示岁。 (days>=6*365)
     */
    public static Integer getCorrectDays(String birthday, Integer pregnancyWeek, String testTime, boolean flag) {
        // TODO Auto-generated method stub
        // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Long time = (long) 0;
        try {
            if (StringUtils.isBlank(birthday)) {
                return 0;
            }
            Date birthdayDate = DateUtil.getDate_8(birthday);

            Calendar now = Calendar.getInstance();
            Calendar cal = Calendar.getInstance();
            cal.setTime(birthdayDate);
            if (!StringUtils.isBlank(testTime)) {
                Date testTimeDate = DateUtil.getDate_8(testTime);
                now.setTime(testTimeDate);
                time = testTimeDate.getTime();
            } else {
                time = new Date().getTime();
            }
            int year = now.get(Calendar.YEAR) - cal.get(Calendar.YEAR);
            int day = now.get(Calendar.DAY_OF_MONTH) - cal.get(Calendar.DAY_OF_MONTH);
            int month = now.get(Calendar.MONTH) - cal.get(Calendar.MONTH);

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。

            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }
            time = time - birthdayDate.getTime();
            if (flag) {
                if (null == pregnancyWeek || 0 == pregnancyWeek || pregnancyWeek >= 259
                        || (year >= 2 && month >= 0 && day >= 0)) { // 孕周大于37
                    // 或者
                    // 大于2岁
                    // 按正常年龄算
                } else {
                    time = time - (280 - pregnancyWeek) * 86400000L;
                }
            }
        } catch (Exception e) {
            logger.error("计算年龄报错", e);
        }

        int days = (int) (time / 86400000L);
        return days;
    }

    public static boolean delAllFile(String path) {
        boolean flag = false;
        File file = new File(path);
        if (!file.exists()) {
            return flag;
        }
        if (!file.isDirectory()) {
            return flag;
        }
        String[] tempList = file.list();
        File temp = null;
        for (int i = 0; i < tempList.length; i++) {
            if (path.endsWith(File.separator)) {
                temp = new File(path + tempList[i]);
            } else {
                temp = new File(path + File.separator + tempList[i]);
            }
            if (temp.isFile()) {
                temp.delete();
            }
            if (temp.isDirectory()) {
                delAllFile(path + "/" + tempList[i]);// 先删除文件夹里面的文件
                flag = true;
            }
        }
        return flag;
    }

    /**
     * @name: 字符串list，即 "[\"11\",\"22\"]" ---> ["11","22"]
     * @author: DemonLee
     * @createTime: 2018.5.27
     * @param: 待解析的string, List
     * @return:
     * @modify:
     */
    public static void parseStringToList(String oriStr, List<String> newList) {
        if (null == newList) {
            return;
        }
        if (StringUtils.isNotBlank(oriStr) && oriStr.length() > 1) {
            // 去除中括号
            String strValue = oriStr.substring(1, oriStr.length() - 1);
            // 去除双引号
            strValue = strValue.replaceAll("\"", "").replace(" ", "");
            String strArr[] = strValue.split(Constants.COMMA_SPLIT_STR);
            for (String str : strArr) {
                if (StringUtils.isNotBlank(str)) {
                    newList.add(str);
                }
            }
        }

        return;
    }



    /**
     * 产生随机码
     *
     * @param num 多少位随机码
     * @return
     * @version 1.0.0
     */
    public static String getRandom(int num) {
        Random random = new Random();
        StringBuffer str = new StringBuffer();
        for (int i = 0; i < num; i++) {
            str.append(Math.abs(random.nextInt() % 10));
        }

        return str.toString();
    }


    // 阿里注册短信 (新api)
    public static Boolean sendALISmsNew(String phoneNo, String context, String smsType) throws Exception {
        Boolean flag = false;
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", "KxOYldlzgNbV7LPk",
                "Do7wFceam0fGLK3ovbJd2J2rZQRyUh");

        final String product = "Dysmsapi";// 短信API产品名称（短信产品名固定，无需修改）
        final String domain = "dysmsapi.aliyuncs.com";// 短信API产品域名（接口地址固定，无需修改）

        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
        IAcsClient client = new DefaultAcsClient(profile);
        SendSmsRequest request = new SendSmsRequest();

        String templateCode = "SMS_33810202"; // 注册
        if (smsType.equals("02")) {
            templateCode = "SMS_33910139"; // 找回密码
        } else if (smsType.equals("07")) {
            templateCode = "SMS_67255538"; // 提现
        }

        try {
            request.setSignName("贝生医疗");
            request.setTemplateCode(templateCode);
            request.setTemplateParam("{\"code\":\"" + context + "\"}");
            request.setPhoneNumbers(phoneNo);
            SendSmsResponse httpResponse = client.getAcsResponse(request);
            if (httpResponse != null) {
                logger.info("aliyun smssend back-->" + httpResponse.getCode() + "--" + httpResponse.getMessage());
                if (httpResponse.getRequestId() != null) {
                    flag = true;
                } else {
                    flag = false;
                }
            } else {
                flag = false;
            }
        } catch (Exception e) {
            logger.error("aliyun smssend error", e);
        }
        return flag;
    }

    // 亿美软通短信-通知类
    public static int sendYMsms(String phoneNo, String context) throws Exception {
        String sn = "8SDK-EMY-6699-RFQPN";// 软件序列号,请通过亿美销售人员获取
        String key = "192329";// 序列号首次激活时自己设定
        // String password = "192329";// 密码,请通过亿美销售人员获取
        String baseUrl = "http://hprpt2.eucp.b2m.cn:8080/sdkproxy/";
        String param = "";
        String message = "【贝生医疗】" + context;
        message = URLEncoder.encode(message, "UTF-8");
        long seqId = System.currentTimeMillis();
        param = "cdkey=" + sn + "&password=" + key + "&phone=" + phoneNo + "&message=" + message + "&seqid=" + seqId;
        String url = baseUrl + "sendsms.action";
        String ret = "";
        try {
            ret = SDKHttpClient.sendSMS(url, param);
        } catch (Exception ex) {
            logger.error("调用外部亿美软通短信接口失败:", ex);
            ret = ErrorCode.EXCEPTION_TYPE_SYSTEM_OUTSMS_SERVICE_CALL_EXCP;// 失败
        }
        logger.info("发送结果:" + ret);
        return Integer.parseInt(ret);
    }

    // 亿美软通短信-通知类
    public static int sendYMsms2(String phoneNo, String context) throws Exception {
        String sn = "8SDK-EMY-6699-RFQPN";// 软件序列号,请通过亿美销售人员获取
        String key = "192329";// 序列号首次激活时自己设定
        // String password = "192329";// 密码,请通过亿美销售人员获取
        String baseUrl = "http://hprpt2.eucp.b2m.cn:8080/sdkproxy/";
        String param = "";
        String message = context;
        message = URLEncoder.encode(message, "UTF-8");
        long seqId = System.currentTimeMillis();// 获取当前系统时间
        param = "cdkey=" + sn + "&password=" + key + "&phone=" + phoneNo + "&message=" + message + "&seqid=" + seqId;
        String url = baseUrl + "sendsms.action";
        // System.out.println("短信即将发送请注意:" + seqId);
        String ret = "";
        try {
            ret = SDKHttpClient.sendSMS(url, param);
        } catch (Exception ex) {
            logger.error("调用外部亿美软通短信接口失败:", ex);
            ret = ErrorCode.EXCEPTION_TYPE_SYSTEM_OUTSMS_SERVICE_CALL_EXCP;// 失败
        }
        // System.out.println("发送结果:" + ret);
        return Integer.parseInt(ret);
    }

    public static int sendYMsms3(String phoneNo, String context) throws Exception {
        String sn = "6SDK-EMY-6666-RHWLN";// 软件序列号,请通过亿美销售人员获取
        String key = "203969";// 序列号首次激活时自己设定
        // String password = "203969";// 密码,请通过亿美销售人员获取
        String baseUrl = "http://sdktaows.eucp.b2m.cn:8080/sdkproxy/";
        String param = "";
        context = URLEncoder.encode(context, "UTF-8");
        long seqId = System.currentTimeMillis();
        param = "cdkey=" + sn + "&password=" + key + "&phone=" + phoneNo + "&message=" + context + "&seqid=" + seqId;
        String url = baseUrl + "sendsms.action";

        // String ret = SDKHttpClient.registAndLogout(url, param);
        String ret = "";
        try {
            ret = SDKHttpClient.sendSMS(url, param);
        } catch (Exception ex) {
            logger.error("调用外部亿美软通短信接口失败:", ex);
            ret = ErrorCode.EXCEPTION_TYPE_SYSTEM_OUTSMS_SERVICE_CALL_EXCP;// 失败
        }
        logger.info(param);
        logger.info("发送结果:" + ret);
        return Integer.parseInt(ret);
    }

    /**
     * 将问卷id转换成key：value格式 ,value包含题目的所有配置
     */
    public static Map<String, Object> tranferCpContentToMap(Object content) {
        if (null == content) {
            return null;
        }
        Map<String, Object> contentMap = new HashMap<String, Object>();
        // for(int j =0,m=contentList.size();j<m;j++){
        if (content instanceof com.alibaba.fastjson.JSONArray) {
            com.alibaba.fastjson.JSONArray arr = (com.alibaba.fastjson.JSONArray) content;
            for (int k = 0; k < arr.size(); k++) {
                com.alibaba.fastjson.JSONArray chirldArr = arr.getJSONObject(k).getJSONArray("children");
                if (null != chirldArr) {
                    chirldJsonCpToMap(contentMap, chirldArr);
                } else {
                    questionJsonCpToMap(contentMap, arr.getJSONObject(k));
                }
            }
        } else if (content instanceof JSONObject) {
            com.alibaba.fastjson.JSONArray chirldArr = ((com.alibaba.fastjson.JSONObject) content)
                    .getJSONArray("children");
            if (null != chirldArr) {
                chirldJsonCpToMap(contentMap, chirldArr);
            } else {
                questionJsonCpToMap(contentMap, (com.alibaba.fastjson.JSONObject) content);
            }

        }
        // }
        return contentMap;
    }

    /**
     * 解析一个{}中 ，只是一个题目的情况
     */
    public static void questionJsonCpToMap(Map<String, Object> contentMap, JSONObject json) {
        if (null == json) {
            return;
        }

        if (!StringUtils.isEmpty(json.getString("deCode"))) {
            contentMap.put(json.getString("deCode"), json);
        }
    }

    public static void chirldJsonCpToMap(Map<String, Object> contentMap, com.alibaba.fastjson.JSONArray chirldArr) {
        for (int l = 0; l < chirldArr.size(); l++) {
            Object deCode = chirldArr.getJSONObject(l).getObject("deCode", Object.class);
            if (!org.springframework.util.StringUtils.isEmpty(deCode)) {
                if (deCode instanceof String) {
                    contentMap.put(deCode.toString(), chirldArr.getJSONObject(l));
                } else if (deCode instanceof com.alibaba.fastjson.JSONArray) {
                    com.alibaba.fastjson.JSONArray idArr = (com.alibaba.fastjson.JSONArray) deCode;
                    for (int n = 0; n < idArr.size(); n++) {
                        contentMap.put(idArr.getString(n), chirldArr.getJSONObject(l));
                    }
                }
            } else {
                JSONArray deCodeArr = chirldArr.getJSONObject(l).getJSONArray("list");
                String relationId = chirldArr.getJSONObject(l).getString("relationId");
                if (!StringUtils.isEmpty(relationId)) {
                    com.alibaba.fastjson.JSONArray jsonArr = chirldArr.getJSONObject(l).getJSONArray("children");
                    if (null != jsonArr) {
                        for (int n = 0; n < jsonArr.size(); n++) {
                            String chirldDeCode = jsonArr.getJSONObject(n).getString("deCode");
                            if (!StringUtils.isEmpty(chirldDeCode)) {
                                contentMap.put(chirldDeCode, jsonArr.getJSONObject(n));
                            }
                        }
                    }
                }

                if (null != deCodeArr) {
                    for (int n = 0; n < deCodeArr.size(); n++) {
                        String chirldDeCode = deCodeArr.getJSONObject(n).getString("deCode");
                        if (!StringUtils.isEmpty(chirldDeCode)) {
                            contentMap.put(chirldDeCode, deCodeArr.getJSONObject(n));
                        }
                    }
                }
            }
        }
    }

    /**
     * 日期格式转换（yyyy-MM-dd)
     *
     * @param date
     * @return
     */
    public static String date2Str(Date date) {
        return dateFormat.format(date);
    }

    /**
     * 返回计算年龄，孕周 早产等信息
     *
     * @throws Exception
     */
    public static void showAgeAndPreDay(Map<String, Object> map) throws Exception {
        String birthFlag = "";// 是否早产
        String currDay = DateUtil.getCurrDate2();
        String birthdayStr = MapUtils.getString(map, "birthday");
        if (StringUtils.isNotBlank(birthdayStr)) {
            String pregnancyDayStr = MapUtils.getString(map, "pregnancyDay");
            if (StringUtils.isNotBlank(pregnancyDayStr)) {
                long correctAge = ToolUtil.getCorrect(birthdayStr, Integer.parseInt(pregnancyDayStr));
                Date date = new Date(correctAge);
                map.put("age", ToolUtil.getAgeByBirthday(DateUtil.getDate_8(date)));
                map.put("ageDay", DateUtil.getDistanceTime(birthdayStr, currDay));
                map.put("pregnancyWeek", ToolUtil.getPregnancyStr(Integer.parseInt(pregnancyDayStr)));

                // 早产$bb.dateDiff(arr[i].birthday,$bb.getCurTime().date).days
                int pregnancyDay = Integer.valueOf(pregnancyDayStr);
                if (DateUtil.getDistanceTime(birthdayStr, currDay) < Constants.BIRTH_DAY
                        && pregnancyDay < Constants.PREGNANCY_DAY) {
                    birthFlag = "Y";
                    Date date0 = DateUtil.getDate_8(birthdayStr);
                    map.put("age", ToolUtil.getAgeByBirthday(DateUtil.getDate_8(date0)));
                    map.put("ageDay", DateUtil.getDistanceTime(DateUtil.getDate_8(date0), currDay));
                } else {
                    birthFlag = "N";
                }
            } else {
                // 孕周为空则按正常年龄算
                map.put("age", ToolUtil.getAgeByBirthday(birthdayStr));
                map.put("ageDay", DateUtil.getDistanceTime(birthdayStr, currDay));
            }
        } else {
            map.put("age", "");
            map.put("ageDay", 0);
        }
        map.put("birthFlag", birthFlag);
    }

    /**
     * 深度拷贝
     *
     * @date 2018年6月19日
     */
    public static <T extends Serializable> T clone(T obj) {
        T clonedObj = null;
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(obj);
            oos.close();
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            clonedObj = typeCast(ois.readObject());
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return clonedObj;
    }

    /**
     * 校验入参中节点是否为空 checkNode: 校验的节点名称; argInfo: 校验入参源; checkVarInfo: 待校验的变量
     * 支持各种类型的数据是否为空
     **/
    public static void checkInputMultiNew(String checkNode, Map<String, Object> argInfo,
                                          List<Map<String, Object>> checkVarList) {
        if (CollectionUtils.isEmpty(checkVarList)) {
            return;
        }
        if (MapUtils.isEmpty(argInfo)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + checkNode + "节点为空！"));
        }

        String chkVarId = null;// 校验变量名
        String chkVarName = null;// 校验变量中文名
        Integer chkVarType = null;// 校验变量的类型
        Integer chkRuleType = null;// 校验规则
        String format = null;// 具体日期格式 ，不传 默认： yyyy-MM-dd E HH:mm:ss

        int c = 0;
        int csize = checkVarList.size();
        Map<String, Object> chekVarMap = new HashMap<String, Object>();
        for (c = 0; c < csize; c++) {
            chekVarMap = checkVarList.get(c);
            if (MapUtils.isEmpty(chekVarMap)) {
                continue;
            }
            chkVarId = MapUtils.getString(chekVarMap, "chkVarId");
            chkVarName = MapUtils.getString(chekVarMap, "chkVarName");
            chkVarType = (Integer) chekVarMap.get("chkVarType");
            chkRuleType = (Integer) chekVarMap.get("chkRuleType");
            format = MapUtils.getString(chekVarMap, "format");
            switch (chkRuleType) {
                // 入参不能为空 一般string类型校验
                case Constants.CHECK_TYPE_FOR_NOTNULL: {
                    // 非空
                    if (org.springframework.util.StringUtils.isEmpty(argInfo.get(chkVarId))) {
                        throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                                chkVarName + "不能为空！"));
                    }
                    break;
                }
                // 入参必须大于0 数字型校验
                case Constants.CHECK_TYPE_FOR_NOTNULL_AND_GEZERO: {
                    Object chkValue = argInfo.get(chkVarId);
                    if (org.springframework.util.StringUtils.isEmpty(chkValue)) {
                        throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                                chkVarName + "不能为空！"));
                    }
                    // 必须为数字
                    boolean flag = isNumeric(MapUtils.getString(argInfo, chkVarId));
                    if (!flag) {
                        throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                                Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + chkVarName + "传值错误！"));
                    }

                    // integer
                    if (Constants.COMMON_TYPE_FOR_INTEGER == chkVarType) {
                        int num = Integer.parseInt(chkValue.toString());
                        if (num < 0) {
                            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + chkVarName + "传值错误！"));
                        }
                    } else if (Constants.COMMON_TYPE_FOR_FLOAT == chkVarType) {
                        float num = Float.parseFloat(chkValue.toString());
                        if (num < 0) {
                            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + chkVarName + "传值错误！"));
                        }
                    }

                }
                // 入参不能为空 类型、格式正确
                case Constants.CHECK_TYPE_FOR_NOTNULL_FORMAT: {
                    String chkValue = MapUtils.getString(argInfo, chkVarId);
                    if (StringUtils.isBlank(chkValue)) {
                        throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                                chkVarName + "不能为空！"));
                    }
                    checkFormatCommon(chkVarName, chkVarType, format, chkValue);
                    break;
                }
                // 如果入参传值 则格式、类型必须正确
                case Constants.CHECK_TYPE_FOR_FORMAT: {
                    String chkValue = MapUtils.getString(argInfo, chkVarId);
                    if (!StringUtils.isBlank(chkValue)) {
                        checkFormatCommon(chkVarName, chkVarType, format, chkValue);
                    }
                    break;
                }
            }
        }

        return;
    }

    private static void checkFormatCommon(String chkVarName, Integer chkVarType, String format, String chkValue)
            throws AppException {
        // 必须为数字类型
        if (Constants.COMMON_TYPE_FOR_INTEGER == chkVarType || Constants.COMMON_TYPE_FOR_FLOAT == chkVarType) {
            boolean flag = isNumeric(chkValue);
            if (!flag) {
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                        Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + chkVarName + "传值错误！"));
            }
        } else if (Constants.COMMON_TYPE_FOR_DATE == chkVarType) {
            if (StringUtils.isBlank(format)) {
                format = DateUtil.FORMAT_JAVA_A;
            }
            if (!DateUtil.isValidDate(chkValue, format)) {
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                        Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + chkVarName + "传值错误！"));
            }
        }
    }

    // BMI<18.5低体重、BMI18.5 ≥ ～ <24.9标准体重、 BMI25.0～ 29.9超重、BMI ≥ 30.0 肥胖 左闭右开
    public static void tranWeightToBmi(Map<String, Object> arg) {
        // 0 1 2 3
        String weight = MapUtils.getString(arg, "weight");
        String beginWeight = "";
        String endWeight = "";
        if ("0".equals(weight)) {
            endWeight = "18.5";
        } else if ("1".equals(weight)) {
            beginWeight = "18.5";
            endWeight = "24.9";
        } else if ("2".equals(weight)) {
            beginWeight = "24.9";
            endWeight = "29.9";
        } else if ("3".equals(weight)) {
            beginWeight = "29.9";
            endWeight = "";
        }
        arg.put("beginWeight", beginWeight);
        arg.put("endWeight", endWeight);
    }

    // 根据出生日期和预产期计算孕周，返回天数
    public static int calPrenDayByLastMenstrual(String lastMenstrual) {
        int day = 0;
        if (!StringUtils.isEmpty(lastMenstrual)) {
            try {
                Date lastMenstrualDate = DateUtil.getDate_8(lastMenstrual);

                Calendar last = Calendar.getInstance();
                Calendar now = Calendar.getInstance();
                last.setTime(lastMenstrualDate);
                now.setTime(new Date());
                long lastTime = last.getTimeInMillis();
                long nowTime = now.getTimeInMillis();
                long bet = nowTime - lastTime;
                day = (int) (bet / 86400000L);
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_DATE_PARSE_ERROR, "时间解析错误，格式不正确！"));
            }
        }
        return day;
    }

    /**
     * @param list
     * @param key  暂时 value为整数 参数说明
     * @Title: sortList
     * @Description:
     */
    public static void sortListByInteger(List<Map<String, Object>> list, final String key) {
        Collections.sort(list, new Comparator<Map<String, Object>>() {
            public int compare(Map<String, Object> tempA, Map<String, Object> tempB) {
                int idA = Integer.parseInt(tempA.get(key).toString());
                int idB = Integer.parseInt(tempB.get(key).toString());
                if (idA < idB) {
                    return -1;
                } else if (idA > idB) {
                    return 1;
                } else {
                    return 0;
                }
            }
        });
    }

    /**
     * 验证对象属性是否为空
     *
     * @param <T>
     * @param data
     */
    public static <T> T fieldNotNullValid(Map<String, Object> data, String argName, String[] notNullFieldNames,
                                          Class<T> clazz) {
        T t = json2Obj(data, argName, clazz);
        FieldNotNullCheck.fieldNotNullValid(t, notNullFieldNames);
        return t;
    }

    /**
     * @param data
     * @param argName
     * @param clazz
     * @return
     */
    public static <T> T json2Obj(Map<String, Object> data, String argName, Class<T> clazz) {
        String argValue = data.get(argName) != null ? data.get(argName).toString() : "{}";
        T t = JSONObject.parseObject(argValue, clazz);
        return t;
    }

    // 将阿拉伯数字转化成汉字
    public static String toChineseStr(int number) {
        String[] hanArr = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};
        String[] unitArr = {"十", "百", "千", "万", "十万", "百万", "千万", "亿", "十亿", "百亿", "千亿"};
        String numStr = number + "";
        String result = "";
        int numLen = numStr.length();
        for (int i = 0; i < numLen; i++) {
            int num = numStr.charAt(i) - 48;
            if (i != numLen - 1 && num != 0) {
                result += hanArr[num] + unitArr[numLen - 2 - i];
                if (number >= 10 && number < 20) {
                    result = result.substring(1);
                }
            } else {
                if (!(number >= 10 && number % 10 == 0)) {
                    result += hanArr[num];
                }
            }
        }
        return result;
    }

    /**
     * 将字符串转换成Map结构
     *
     * @param str 需要转换的字符串
     * @return Map结构数据
     * @throws ParseException
     */
    public static Map<String, Object> stringToMap(String str) {
        Map<String, Object> map = new HashMap<String, Object>();
        str = str.replaceAll("\\s*", "");
        ;
        if (str.startsWith("{"))
            str = str.substring(1, str.length());
        if (str.endsWith("}"))
            str = str.substring(0, str.length() - 1);
        String[] datas = str.split(",");
        for (String data : datas) {
            String[] d = data.split("=");
            if (d.length == 2) {
                map.put(d[0], d[1]);
            } else {
                int index = data.indexOf("=");
                if (index > 0)
                    map.put(data.substring(0, index), data.substring(index + 1, data.length()));
            }
        }
        return map;
    }

    /**
     * @throws Exception
     * @date 2018年7月5日
     * @description:计算分娩天数，孕周，
     */
    public static void showDeliveryDay(Map<String, Object> map) throws Exception {
        String deliveryDate = MapUtils.getString(map, "deliveryDate");// 分娩日期
        String currDay = DateUtil.getCurrDate2();
        String pregnancyWeek = "";
        int deliveryDay = 0;
        if (StringUtils.isEmpty(deliveryDate)) {
            // 分娩时间为空的时候，根据末次月经计算孕周
            String lastMenstrualDate = MapUtils.getString(map, "lastMenstrualDate");// 末次月经
            if (StringUtils.isNotEmpty(lastMenstrualDate)) {
                deliveryDay = DateUtil.daysBetweenStr(lastMenstrualDate, currDay);
            }
        } else {
            // 分娩后，根据分娩时间去计算孕周
            deliveryDay = DateUtil.daysBetweenStr(deliveryDate, currDay);
            map.put("deliveryDay", deliveryDay);
        }
        pregnancyWeek = ToolUtil.getPregnancyStr(deliveryDay);
        map.put("pregnancyWeek", pregnancyWeek);
    }

    /**
     * 根据身高体重 计算bmi
     */
    public static Double calculateBmi(Double preWeight, Double preHeight) {
        Double bmi = null;
        if (null != preWeight && null != preHeight && preHeight.floatValue() > 0) {
            bmi = BigDecimalUtil.divide(preWeight, BigDecimalUtil.multiply(preHeight / 100, preHeight / 100));
        }
        return bmi;
    }

    // 阶段转时间作为条件
    public static void tranNodeDate(Map<String, Object> arg) {
        String seqFrom = MapUtils.getString(arg, "seqFrom");
        String seqTo = MapUtils.getString(arg, "seqTo");
        String start = "";
        String end = "";
        if (StringUtils.isNotEmpty(seqFrom)) {
            if (!isNumeric(seqFrom)) {
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_FORMAT_ERROR, "年龄传入的参数不为整数！"));
            }
            Integer startDay = Integer.valueOf(seqFrom);
            start = DateUtil.getYesterday(-startDay);
        }
        if (StringUtils.isNotEmpty(seqTo)) {
            if (!isNumeric(seqTo)) {
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_FORMAT_ERROR, "年龄传入的参数不为整数！"));
            }
            Integer endDay = Integer.valueOf(seqTo);
            end = DateUtil.getYesterday(-endDay);
        }
        arg.put("seqTo", start);
        arg.put("seqFrom", end);
    }

    /**
     * 根据分隔符 将字符串分隔成list
     */
    public static List<String> splitStrToList(String str, String split) {
        List<String> strList = null;

        if (!StringUtils.isEmpty(str) && !StringUtils.isEmpty(split)) {
            String[] arr = str.split(split);
            if (null != arr) {
                strList = Arrays.asList(arr);
            }
        }
        return strList;
    }

    // 根据状态转为条件
    public static void tranParturientStatus(Map<String, Object> arg) {
        String paStatus = MapUtils.getString(arg, "parturientStatus");
        // 2种情况之一
        String existsParturient = "";
        // 开始孕周
        String startPregnancyDay = "";
        // 结束孕周
        String endPregnancyDay = "";
        // 状态到分娩日期
        String deliStatusDate = "";
        if (paStatus.equals(ConstantParams.PARTURIENT_STATUS_0)) {
            startPregnancyDay = "0";
            endPregnancyDay = "13";
            existsParturient = "Y";
        } else if (paStatus.equals(ConstantParams.PARTURIENT_STATUS_1)) {
            startPregnancyDay = "13";
            endPregnancyDay = "28";
            existsParturient = "Y";
        } else if (paStatus.equals(ConstantParams.PARTURIENT_STATUS_2)) {
            startPregnancyDay = "28";
            endPregnancyDay = "";
            existsParturient = "Y";
        } else if (paStatus.equals(ConstantParams.PARTURIENT_STATUS_3)) {
            deliStatusDate = DateUtil.getYesterday(ConstantParams.PARTURIENT_DAY);
        } else if (paStatus.equals(ConstantParams.PARTURIENT_STATUS_4)) {
            deliStatusDate = DateUtil.getYesterday(ConstantParams.PARTURIENT_DAY);
        }
        arg.put("existsParturient", existsParturient);
        arg.put("startPregnancyDay", startPregnancyDay);
        arg.put("endPregnancyDay", endPregnancyDay);
        arg.put("deliStatusDate", deliStatusDate);
    }

    public static void tranPreDay(Map<String, Object> arg) {
        String preDayFrom = MapUtils.getString(arg, "preDayFrom");// 孕周开始天数
        String preDayTo = MapUtils.getString(arg, "preDayTo");// 孕周结束天数
        if (StringUtils.isNotEmpty(preDayFrom)) {
            int start = Integer.valueOf(preDayFrom);
            arg.put("preDayTo", DateUtil.getYesterday(-start));
        }
        if (StringUtils.isNotEmpty(preDayTo)) {
            int end = Integer.valueOf(preDayTo);
            arg.put("preDayFrom", DateUtil.getYesterday(-end));
        }

    }

    /**
     * 创建操作日志
     *
     * @param request
     * @param data
     * @param updateAccept
     * @return
     */
    public static Map<String, Object> createOptRecord(HttpServletRequest request, Map<String, Object> data) {
        Map<String, Object> optRecord = new HashMap<String, Object>();
        optRecord.put("id", SeqUtil.getSeqNo(Constants.SEQ_NO_FOR_OPERATION_ID));

        Map<String, Object> oprInfo = ToolUtil.typeCast(data.get("oprInfo"));
        optRecord.put("opCode", oprInfo.get("opCode"));
        optRecord.put("opType", oprInfo.get("opType"));
        optRecord.put("opDesc", oprInfo.get("opNote"));
        optRecord.put("remark", oprInfo.get("optNode"));
        optRecord.put("channelType", oprInfo.get("channelType"));
        optRecord.put("channelId", oprInfo.get("channelId"));
        optRecord.put("busiCategory", Constants.DOCTOR_ACTIVE_BUSI_TYPE_10);
        Calendar now = Calendar.getInstance();
        optRecord.put("month", String.valueOf(now.get(Calendar.MONTH) + 1));
        optRecord.put("day", String.valueOf(now.get(Calendar.DAY_OF_MONTH)));
        optRecord.put("opUserType", Constants.OPCODE_TYPE_DOCTOR);

        Map<String, Object> session = ToolUtil.getSessionInfo(request, Constants.SESSION_ACCOUNT_KEY);
        optRecord.put("userId", session.get("userId"));
        optRecord.put("opUser", session.get("loginId"));
        optRecord.put("opTime", DateUtil.getTimeString(DateUtil.getSysDateA()));
        optRecord.put("tenantId", session.get("tenantId"));
        optRecord.put("authorId", session.get("authorId"));

        optRecord.put("updateAccept", SeqUtil.getSeqNo(Constants.SEQ_NO_FOR_UPDATE_ACCEPT_ID));
        optRecord.put("updateTime", DateUtil.getTimeString(DateUtil.getSysDateA()));
        optRecord.put("updateAuthor", session.get("authorId"));

        return optRecord;
    }

    /**
     * 创建操作日志
     *
     * @param request
     * @param data
     * @param updateAccept
     * @return
     */
    public static void createOptRecordNew(Map<String, Object> optRecord, Map<String, Object> data) {
        optRecord.put("id", SeqUtil.getSeqNo(Constants.SEQ_NO_FOR_OPERATION_ID));

        Map<String, Object> oprInfo = ToolUtil.typeCast(data.get("oprInfo"));
        optRecord.put("opCode", oprInfo.get("opCode"));
        optRecord.put("opType", oprInfo.get("opType"));
        optRecord.put("opDesc", oprInfo.get("opNote"));
        optRecord.put("remark", null);
        optRecord.put("channelType", oprInfo.get("channelType"));
        optRecord.put("channelId", oprInfo.get("channelId"));
        optRecord.put("busiCategory", null);
        Calendar now = Calendar.getInstance();
        optRecord.put("month", String.valueOf(now.get(Calendar.MONTH) + 1));
        optRecord.put("day", String.valueOf(now.get(Calendar.DAY_OF_MONTH)));
        if (Constants.OP_TYPE_SELF.equals(oprInfo.get("opType"))) {
            optRecord.put("opUserType", Constants.OPCODE_TYPE_PATIENT);
        } else {
            optRecord.put("opUserType", Constants.OPCODE_TYPE_DOCTOR);
        }

        Map<String, Object> session = ToolUtil.typeCast(data.get("sessionInfo"));
        // optRecord.put("userId", "");
        // optRecord.put("queueId", "");
        // optRecord.put("busiId", "");
        // optRecord.put("breifIntro", "");
        // optRecord.put("taskId", "");
        String sysDateTime = DateUtil.getSysDateA();
        optRecord.put("opUser", session.get("authorId"));
        optRecord.put("opTime", sysDateTime);
        optRecord.put("tenantId", session.get("tenantId"));
        optRecord.put("projectRoleId", session.get("projectRoleId"));
        optRecord.put("updateAccept", SeqUtil.getSeqNo(Constants.SEQ_NO_FOR_UPDATE_ACCEPT_ID));

        optRecord.put("updateAuthor", session.get("authorId"));
        optRecord.put("updateTime", sysDateTime);
        optRecord.put("authorId", session.get("authorId"));
        optRecord.put("projectId", session.get("projectId"));
        // optRecord.put("logSessionInfo", session);

        return;
    }

    /**
     * 为t对象createTime, createAuthor, updateTime, updateAuthor,
     * updateAccpet属性（如果存在以上属性）赋值
     *
     * @param t
     * @param params
     * @param isCreate 新增或修改
     * @return
     */
    public static <T> T fillField(T t, Map<String, Object> params, boolean isCreate) {

        Method[] methods = t.getClass().getMethods();
        for (Method method : methods) {
            String fieldName = MethodName
                    .getFieldName(method.getName().substring(method.getName().lastIndexOf(".") + 1), isCreate);
            if (fieldName != null) {
                try {
                    method.invoke(t, params.get(fieldName));
                } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        return t;
    }

    public static String Encrept(String password) throws Exception {
        password = password + ConstantParams.SECRET_KEY;
        password = changeToSHA(password, ConstantParams.COMMON_SHA_256);
        password = MD5Encrept(password, ConstantParams.COMMON_MD5_32);
        return password;
    }

    /**
     * SHA-256 和 SHA-512j加密 输入参数：
     *
     * @param strText String 需要加密的字符串
     * @param strType String SHA-256 和 SHA-512 两种 Hash 算法 输出参数
     * @param 加密后的出参  String 异或运算后的字符串
     * @throws UnsupportedEncodingException
     * @throws Exception
     * @author wuyz
     * @createTime 2017.06.13
     **/
    public static String changeToSHA(String strText, String strType) throws UnsupportedEncodingException {
        // 返回值
        String strResult = "";

        // 是否是有效字符串
        if (strText != null && strText.length() > 0) {
            try {
                // SHA 加密开始
                // 创建加密对象 并傳入加密類型
                MessageDigest messageDigest = MessageDigest.getInstance(strType);
                // 传入要加密的字符串
                messageDigest.update(strText.getBytes("UTF-8"));
                // 得到 byte 类型结果
                byte byteBuffer[] = messageDigest.digest();
                BASE64Encoder encode = new BASE64Encoder();
                strResult = encode.encode(byteBuffer);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
        strResult = strResult.toLowerCase();
        return strResult;
    }

    /**
     * md5加密函数 入参参数描述：
     *
     * @param sourceStr String 需要加密的字符串
     * @param flag      int 需要加密的位数：（1）32：返回32位加密串 （2）16：返回16位加密串 返回参数：
     * @return sourceStr String MD5加密后的字符串
     * @createTime 2017.06.13
     * @author wuyz
     **/
    public static String MD5Encrept(String sourceStr, int flag) throws Exception {
        String result = "";
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(sourceStr.getBytes());
            byte b[] = md.digest();
            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                    i += 256;
                if (i < 16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            if (flag == 32) {
                result = buf.toString();
            } else {
                result = buf.toString().substring(8, 24);
            }
        } catch (NoSuchAlgorithmException e) {
            throw new NoSuchAlgorithmException(e.toString());
        }
        return result;
    }

    public static List<String> parseStringToList(String oriStr) {
        List<String> list = new ArrayList<>();
        if (null == oriStr) {
            return list;
        }
        if (StringUtils.isNotBlank(oriStr) && oriStr.length() > 1) {

            String strArr[] = oriStr.split(Constants.COMMA_SPLIT_STR);
            for (String str : strArr) {
                if (StringUtils.isNotBlank(str)) {
                    list.add(str);
                }
            }
        }

        return list;
    }

    public static enum MethodName {
        // 创建对象时 create与update信息一样
        CREATETIME("setCreateTime", "updateTime"), CREATEAUTHOR("setCreateAuthor", "updateAuthor"), UPDATETIME(
                "setUpdateTime", "updateTime"), UPDATEAUTHOR("setUpdateAuthor",
                "updateAuthor"), UPDATEACCEPT("setUpdateAccept", "updateAccept");

        private String methodName;
        private String fieldName;

        public String getMethodName() {
            return methodName;
        }

        public void setMethodName(String methodName) {
            this.methodName = methodName;
        }

        public String getFieldName() {
            return fieldName;
        }

        public void setFieldName(String fieldName) {
            this.fieldName = fieldName;
        }

        private MethodName(String methodName, String fieldName) {
            this.methodName = methodName;
            this.fieldName = fieldName;
        }

        static String getFieldName(String value, boolean isCreate) {
            for (MethodName methodName : MethodName.values()) {
                if (value.equals(methodName.getMethodName())) {
                    if (!(isCreate && (methodName.equals("setCreateTime") || methodName.equals("setUpdateTime")))) {
                        return methodName.getFieldName();
                    }
                }
            }
            return null;
        }
    }




    /**
     * 使用原生HTTPclient处理，调用远程服务
     *
     * @param urlName  接口url变量名，apiName 接口变量名
     * @param jsonBody
     * @return
     * @throws Exception
     */
    public static Map<String, Object> httpClientPost(String urlName, String apiName, String jsonBody) throws Exception {
        String urlValue = PropertiesUtils.getProperty(urlName);
        if (StringUtils.isBlank(urlValue)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    urlName + "配置地址为空，请联系系统管理员！"));
        }
        String apiValue = PropertiesUtils.getProperty(apiName);
        if (StringUtils.isBlank(apiValue)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    apiName + "接口路径配置为空，请联系系统管理员！"));
        }
        Map<String, Object> msgMap = null;
        String msg = null;
        Boolean isSuccess = false;
        String url = urlValue + apiValue;
        String resultStr = HttpUtil.postData(url, jsonBody);
        if (StringUtils.isNotBlank(resultStr)) {
            try {
                msgMap = JSON.parseObject(resultStr);
                isSuccess = MapUtils.getBoolean(msgMap, "success");
                if (isSuccess) {
                    // 调用成功
                } else {
                    isSuccess = false;
                    msg = MapUtils.getString(msgMap, "msg");
                }
            } catch (JSONException ex) {
                // 返回不是json格式
                msg = resultStr;
            }
        }
        if (!isSuccess) {
            logger.error("调用接口【" + apiName + "】异常：" + msg);
            throw new AppException(ErrorCode.EXCEPTION_CSB_SERVICE_CALL, "调用接口异常：" + msg);
        }

        return msgMap;
    }

    /**
     * 字符串list转string
     * "[\"111\",\"33\"]" --> 111,33
     *
     * @param value
     * @return
     */
    public static String list2Str(String value) {
        if (StringUtils.isBlank(value) || value.length() < 2) {
            return value;
        } else if ("[]".equals(value)) {
            return "";
        }
        // 去掉首尾[]
        if (']' == value.charAt(value.length() - 1)) {
            value = value.substring(0, value.length() - 1);
        }
        if ('[' == value.charAt(0)) {
            value = value.substring(1, value.length());
        }
        // 去掉双引号
        value = value.replace("\"", "");

        return value;
    }

    // 检测日期对应的矫正年龄
    public static Long getCorrectCheckAge(Map<String, Object> mapIn) {
        String birthday = (String) mapIn.get("birthday");
        Integer pregnancyWeek = (Integer) mapIn.get("pregnancyDay");
        String checkDate = (String) mapIn.get("checkDate");
        Long time = new Date().getTime();
        try {
            Date birthdayDate = DateUtil.getDate_8(birthday);

            Calendar now = Calendar.getInstance();
            now.setTime(DateUtil.getDate_8(checkDate));

            Calendar cal = Calendar.getInstance();
            cal.setTime(birthdayDate);
            int year = now.get(Calendar.YEAR) - cal.get(Calendar.YEAR);
            int day = now.get(Calendar.DAY_OF_MONTH) - cal.get(Calendar.DAY_OF_MONTH);
            int month = now.get(Calendar.MONTH) - cal.get(Calendar.MONTH);

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。

            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }
            if (null == pregnancyWeek || 0 == pregnancyWeek || pregnancyWeek >= 259
                    || (year >= 2 && month >= 0 && day >= 0)) { // 孕周大于37
                // 或者
                // 大于2岁
                // 按正常年龄算
                time = birthdayDate.getTime();
            } else {
                time = birthdayDate.getTime() + (280 - pregnancyWeek) * 86400000L;
            }
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return time;
    }
}
